<?php
/**
 * Http Client
 *
 * @author Ferman Yee <fermanyee@163.com>
 * @copyright 2018-11-6
 */

namespace XppOpenApi\Util;

class HttpClient {

    protected $header = array();
    
    protected $connectTimeout = 30000;
    
    protected $timeout = 30000;
    
    protected $config = array();
    
    protected $info = array();
    
    /**
     * HttpClient
     * @param array $headers HTTP header
     */
    public function __construct($headers = array()) {
        $this->headers = $this->buildHeaders($headers);
        $this->config = array();
    }

    /**
     * 连接超时
     * @param int $ms 毫秒
     */
    public function setConnectionTimeoutInMillis($ms) {
        $this->connectTimeout = $ms;
    }

    /**
     * 响应超时
     * @param int $ms 毫秒
     */
    public function setTimeoutInMillis($ms) {
        $this->timeout = $ms;
    }    

    /**
     * @param  string $url
     * @param  array $data HTTP POST BODY
     * @param  array $param HTTP URL
     * @param  array $headers HTTP header
     * @return array
     */
    public function post($url, $data = array(), $params = array(), $headers = array()) {
        return $this->request($url, 'POST', $data, $params, $headers);
    }

    /**
     * @param  string $url
     * @param  array $param HTTP URL
     * @param  array $headers HTTP header
     * @return array
     */
    public function get($url, $params = array(), $headers = array()) {
        return $this->request($url, 'GET', array(), $params, $headers);
    }
    
    private function request($url, $method = 'GET', $data = array(), $params = array(), $headers = array()) {
        $this->info = array();
        $times = array('start_time' => microtime(true));
        $url = $this->buildUrl($url, $params);
        $this->setInfo('url', $url);
        $method = strtolower($method);
        $headers = array_merge($this->headers, $this->buildHeaders($headers));
        
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);
        if ($method == 'post') {
            curl_setopt($ch, CURLOPT_POST, 1);
            if (is_array($data)) {
                if (version_compare(PHP_VERSION, '5.4.0','<')) {
                    $data = preg_replace_callback("#\\\u([0-9a-f]{4})#i", function ($matches) {
                        return iconv('UCS-2BE', 'UTF-8', pack('H4', $matches[1]));
                    }, json_encode($data));
                } else {
                    $data = json_encode($data, JSON_UNESCAPED_UNICODE);
                }
                curl_setopt($ch, CURLOPT_HTTPHEADER, array('content-type:application/json'));
            }
            curl_setopt($ch, CURLOPT_POSTFIELDS, is_array($data) ? http_build_query($data) : $data);
            $this->setInfo('post', $data);
        }
        curl_setopt($ch, CURLOPT_HEADER, false);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
        curl_setopt($ch, CURLOPT_TIMEOUT_MS, $this->timeout);
        curl_setopt($ch, CURLOPT_CONNECTTIMEOUT_MS, $this->connectTimeout);
        $content = curl_exec($ch);
        $code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        
        if ($code === 0) {
            throw new \Exception(curl_error($ch));
        }
        
        curl_close($ch);
        
        $times['end_time'] = microtime(true);
        $times['exec_time'] = round($times['end_time'] - $times['start_time'], 4);
        $this->setInfo('times', $times);
        $this->setInfo('code', $code);
        $this->setInfo('response', $content);
        
        return array(
            'code' => $code,
            'content' => $content,
        );
    }

    /**
     * 构造 header
     * @param  array $headers
     * @return array
     */
    private function buildHeaders($headers) {
        $result = array();
        foreach($headers as $k => $v){
            $result[] = sprintf('%s:%s', $k, $v);
        }
        return $result;
    }

    /**
     * 
     * @param  string $url
     * @param  array $params 参数
     * @return string
     */
    private function buildUrl($url, $params){
        if(!empty($params)){
            $str = http_build_query($params);
            return $url . (strpos($url, '?') === false ? '?' : '&') . $str;
        }else{
            return $url;
        }
    }
    
    public function setInfo($key, $value) {
        $this->info[$key] = $value;
    }
    
    public function getInfo($key = null) {
        if (!is_null($key)) {
            return $this->info[$key];
        }
        return $this->info;
    }
}
